Zum Hauptinhalt springen

Neue FastReport-Version: Bekannte Darstellungsprobleme bei älteren Reports und deren Behebung

(Stand: 11/2026)

Verfügbar ab Release: 2.0.2611.x

Verfügbar in Subscription: Core · Pro · Ultimate

Betrifft: ⚙️ Administration

Hintergrund​

Mit der aktuellen Version von NEXOWARE c-entronERP setzen wir eine neue Version der Report-Engine (FastReport) ein. Das Update ist notwendig: Unter anderem wird damit das Problem mit der Glyphenbreite bei ZUGFeRD-PDFs automatisch behoben, ohne dass du deinen Report anpassen musst.

Der aktuelle Hybrid Kundenanlagen Report Version 26-5-2-SP ist bereits auf die neue Engine abgestimmt. Wenn du einen älteren oder individuell angepassten Belegreport weiterverwendest, kann es vereinzelt zu Darstellungsfehlern kommen. In dieser FAQ beschreiben wir die bislang bekannten Effekte und wie du sie in deinem bestehenden Report selbst beheben kannst.


Welche Reports sind betroffen?​

Betroffen sind vor allem Belege mit Rich-Text-Inhalten, also in erster Linie Kundenbelege wie Angebote, Aufträge, Lieferscheine oder Rechnungen. Je nach Aufbau können auch Verträge, Serviceberichte oder angehängte Checklisten betroffen sein.


Wie gehe ich am besten vor?​

Unsere Empfehlung: aktuellen Standard-Report verwenden

Am einfachsten ist der Umstieg auf den aktuellen Hybrid Kundenanlagen Report Version 26-5-2-SP. Er enthält bereits alle Korrekturen und steht im Report-Portal zur Verfügung. Deine individuellen Anpassungen überträgt unser Consulting gerne für dich.

Du möchtest deinen eigenen Report weiterverwenden?

Kein Problem. Prüfe ihn nach dem Update kurz, ob in deiner Testdatenbank oder direkt über die Vorschau, entscheidest du selbst.

  1. Rufe pro Belegart die Vorschau eines Belegs auf, idealerweise mit längeren Positionstexten und Aufzählungszeichen.
  2. Prüfe die Vorschau bzw. das PDF auf die unten beschriebenen Fehlerbilder.
  3. Falls ein Fehler auftritt: Erstelle vor jeder Änderung eine Kopie deines Reports und führe die Anpassung zuerst an der Kopie durch.

Problem 1: Überlappende Texte​

Fehlerbild​

Rich-Text-Inhalte (z. B. Positionstexte) werden übereinander gedruckt, etwa mit Zeilen- oder Spaltenüberschriften. Der Fehler tritt sporadisch auf und erst mit der neuen FastReport-Version.

Screenshot: überlappender Text im Beleg

Ursache​

Im Report liegen Rich-Text- und Plain-Text-Objekte übereinander, damit je nach Inhalt umgeschaltet werden kann. Die endgültige Lösung muss vom Hersteller FastReport geliefert werden; der Fehler ist dort gemeldet und nachvollziehbar. Bis dahin hilft der folgende Workaround nach bisherigen Erfahrungen in nahezu allen Fällen.

Lösung​

Die Lösung wird im Codebereich des Reports eingefügt. Dort werden automatisch alle Rich-Text-Elemente des gesamten Reports berücksichtigt (auch z. B. auf der Titelseite), sodass du nicht jedes Objekt einzeln im Designer ändern musst.

  1. Öffne den Report im Report Designer und wechsle in den Codebereich.
  2. Suche nach tobjRich.Fill = new GlassFill(Color.Transparent, 0, false);
  3. Ergänze an dieser Stelle in der nächsten Codezeile:
tobjRich.ShiftMode = ShiftMode.Never; //hilft bei Text-Überlappungen

Screenshot: überlappender Text im Beleg

  1. Speichere den Report und prüfe den Testbeleg erneut.

Hinweis zur Suche im Report Designer: Falls die Suche einen Begriff nicht findet, aktiviere die Option „Groß-/Kleinschreibung beachten“ (Match case). Ohne diese Option findet die Suche in der neuen Engine Begriffe aktuell teilweise nicht.


Problem 2: Aufzählungszeichen und Abstände​

Fehlerbild​

  • Aufzählungen werden fortgeführt, obwohl sie beendet sind.
  • Abstände sind zu eng oder zu groß, oder Folgezeilen beginnen unter dem Aufzählungszeichen statt eingerückt.
  • Blickfangpunkte oder Sonderzeichen wie • (Alt+0149) werden nicht korrekt dargestellt.
  • Text läuft über den Rand hinaus.

Screenshot: fehlerhafte Aufzählungszeichen

Hinweis: Dieses Verhalten konnte auch vor dem Update bereits auftreten und ist im aktuellen Hybrid Kundenanlagen Report Version 26-5-2-SP behoben. Die folgende Anpassung behebt es auch in deinem eigenen Report dauerhaft.

Schritt 1: Prüfen, ob dein Report für die Selbstanpassung geeignet ist​

Suche im Codebereich nach CheckRichText.

  • Gefunden: Dein Report ist ein Hybrid Kundenanlagen Report ab Version 23-4-0-SP. Mach mit Schritt 2 weiter.
  • Nicht gefunden: Dein Report ist älter als Version 23-4-0-SP. Eine Selbstanpassung ist hier nicht möglich. Lies bitte den Abschnitt Mein Report ist älter als Version 23-4-0-SP.

Schritt 2: Funktionsblock ersetzen​

  1. Suche im Codebereich nach CommercialRound.
  2. Markiere alles direkt nach der Funktion CommercialRound bis einschließlich zum Ende der Funktion CheckRichText. Die Funktion CommercialRound selbst bleibt unverändert. Du kannst die Funktion zusammenklappen: Screenshot: fehlerhafte Aufzählungszeichen
  3. Lösche den markierten Bereich.
  4. Füge an derselben Stelle den neuen Codeblock ein:
    //Umwandlung von Richtext in Text
private string RtfToText(string rtf)
{
// RichTextBox nach Gebrauch freigeben (Dispose), sonst bleibt das Fenster-Handle belegt -> bei großen Belegen
// "Fehler beim Erstellen des Fensterhandles". Bewusst try/finally statt using (wegen FastReport 2022.1.6)
var rtb = new System.Windows.Forms.RichTextBox();
try {
rtb.Rtf = rtf; // Weist dem Steuerelement den RTF-String zu
return rtb.Text; // Gibt den reinen Text ohne Steuerzeichen zurück
}
finally {
rtb.Dispose();
}
}

private float korrekturPlatz = 0; //Korrektur für Platz bei Aufzählungspunkten (FR-Fehler "bis rechten Rand")
string FixRtfBulletList (string content)
{
int kWert = 5; //15

if (korrekturPlatz > 0) {
korrekturPlatz = -kWert * pxFaktor_mm;
} else {
korrekturPlatz = 0 * pxFaktor_mm;
}

var listPatternTyp1 = @"\\ls\d+"; // This matches \ls followed by numbers (that's the bad bullet-lists)
var listPatternTyp2 = @"\\pn\\pnlvlblt"; // This matches \pn structure (\pn is the good bullet-list)
string strTyp2 = @"\pn\pnlvlblt\pnf1\pnindent0{\pntext \'B7\tab}{\*\pn\pnlvlblt\pnstart1{\pntxtb\'B7}}";

if ((Regex.IsMatch(content, listPatternTyp1)) || (Regex.IsMatch(content, listPatternTyp2)))
korrekturPlatz = kWert * pxFaktor_mm; // Platz-Korrektur (wieder entfernen wenn von FR gefixt)

// Aktivieren falls Aufzählungszeichen nicht sauber beendet werden
//if (SelectConvertRichtext == (int)Show.An) {
//pgMain_dPos_RichText.ConvertRichText = true;
//}

// Seems like no bad bullet-lists in this RTF
if (Regex.IsMatch(content, listPatternTyp1) == false)
return content;

// Aktivieren falls Aufzählungszeichen nicht sauber beendet werden
//if (SelectConvertRichtext == (int)Show.An) {
//pgMain_dPos_RichText.ConvertRichText = false;
//}

// Replace \lsN with \pn structure (\pn is the good bullet-list)
var modifiedRtf = Regex.Replace(content, listPatternTyp1, strTyp2);

// Remove unneeded stuff
modifiedRtf = RemoveAllInstancesOfGroup(modifiedRtf, @"listtable");
modifiedRtf = RemoveAllInstancesOfGroup(modifiedRtf, @"listoverridetable");
modifiedRtf = RemoveAllInstancesOfGroup(modifiedRtf, @"listtext");

return modifiedRtf;
}

string RemoveAllInstancesOfGroup(string content, string groupName)
{
while (content.Contains(groupName))
{
content = RemoveGroup(content, groupName);
}
return content;
}

string RemoveGroup(string text, string groupName)
{
// Try finding the group
int groupStart = text.IndexOf(@"{\" + groupName, StringComparison.OrdinalIgnoreCase);

// Fall back to optional-group syntax
if (groupStart == -1)
groupStart = text.IndexOf(@"{\*\" + groupName, StringComparison.OrdinalIgnoreCase);

if (groupStart == -1)
return text;

int groupEnd = FindMatchingCurlyBrace(text, groupStart);
return text.Remove(groupStart, groupEnd - groupStart + 1);
}

int FindMatchingCurlyBrace(string text, int openingBraceIndex)
{
int balance = 1; // Start with 1 to count the opening brace at openingBraceIndex

for (int i = openingBraceIndex + 1; i < text.Length; i++)
{
switch (text[i])
{
case '{':
balance++;
break;
case '}':
balance--;
break;
}

// Found the closing brace
if (balance == 0)
return i;
}

return -1;
}

// Richtext über eine RichTextBox neu schreiben lassen:
// - immer: jeder Absatz beginnt mit \pard -> Listen werden korrekt beendet (FR-Fehler bei ConvertRichText:
// Absatz nach einer Liste bekommt sonst noch Nummer/Aufzählungszeichen)
// - optional (trimEnd): Leerzeilen am Ende vom Richtext entfernen
public string NormalizeRichText(string rtf, bool trimEnd)
{
// RichTextBox nach Gebrauch freigeben (siehe RtfToText)
var rtb = new System.Windows.Forms.RichTextBox();
try {
try {
rtb.Rtf = rtf; // Weist dem Steuerelement den RTF-String zu
}
catch (ArgumentException) {
return (rtf); // kein gültiges RTF -> unverändert zurückgeben
}

if (trimEnd) {
// Whitespaces und Zeilenumbrüche am Ende des reinen Textes zählen
int trailingCharsCount = 0;
string text = rtb.Text;

for (int i = text.Length - 1; i >= 0; i--) {
if (char.IsWhiteSpace(text[i])) {
trailingCharsCount++;
}
else {
break;
}
}

// Wenn Leerzeilen vorhanden sind, diese über die Selection entfernen
if (trailingCharsCount > 0) {
rtb.Select(text.Length - trailingCharsCount, trailingCharsCount);
rtb.SelectedText = "";
}
}
return rtb.Rtf;
}
finally {
rtb.Dispose();
}
}

private string FixRtfSpecialChars(string rtf)
{
// Steuerwort inkl. optionalem Leerzeichen als Trenner ersetzen (nicht bei maskiertem Backslash "\\")
var regex = new Regex(@"(?<!\\)\\(bullet|lquote|rquote|ldblquote|rdblquote)(?![A-Za-z]) ?");
return regex.Replace(rtf, m => {
switch (m.Groups[1].Value) {
case "bullet": return @"\u8226\'95";
case "lquote": return @"\u8216\'91";
case "rquote": return @"\u8217\'92";
case "ldblquote": return @"\u8220\'93";
default: return @"\u8221\'94"; // rdblquote
}
});
}

// Bei ConvertRichText setzt FastReport den Punkt einer Aufzählung (\pnlvlblt) direkt vor den Text:
// kein Abstand nach dem Punkt und umbrochene Zeilen beginnen unter dem Punkt statt unter dem Text.
// Ohne die Listendefinition {\*\pn\pnlvlblt ...} und mit {\pntext \'95\tab} erzeugt FastReport für den
// Punkt ein eigenes Objekt (wie bei nummerierten Listen) -> korrekter hängender Einzug.
private string FixRtfBulletIndent(string rtf)
{
// {\*\pn\pnlvlblt ... {\pntxtb\'B7}}
rtf = Regex.Replace(rtf, @"\{\\\*\\pn\\pnlvlblt[^{}]*(\{[^{}]*\}[^{}]*)*\}", "");
// {\pntext\f1\'B7\tab} or {\pntext \'B7\tab}
rtf = Regex.Replace(rtf, @"\{\\pntext(\\f\d+)?\s?\\'[bB]7\\tab\}", @"{\pntext \'95\tab}");
return rtf;
}

private string checkRichtext(string richtext)
{
// Richtext-Zusatzinformation "themedata" ausblenden
if (richtext.IndexOf("\\*\\themedata") > 0) {
var regex = new Regex(@"{\\\*\\themedata[A-Fa-f0-9\s]*}");
richtext = regex.Replace(richtext, string.Empty);
}

// Richtext-Zusatzinformation "colorschememapping" ausblenden
if (richtext.IndexOf("\\*\\colorschememapping") > 0) {
var regex = new Regex(@"{\\\*\\colorschememapping[A-Fa-f0-9\s]*}");
richtext = regex.Replace(richtext, string.Empty);
}

// "_dx_frag_StartFragment" ausblenden (sind wohl leere Bookmarks)
// exakte Einträge: "{\*\bkmkstart _dx_frag_StartFragment}" + "{\*\bkmkend _dx_frag_StartFragment}"
if (richtext.IndexOf("_dx_frag_StartFragment") > 0) {
var regex = new Regex(@"{\\\*\\bkmkstart _dx_frag_StartFragment}");
richtext = regex.Replace(richtext, string.Empty);
regex = new Regex(@"{\\\*\\bkmkend _dx_frag_StartFragment}");
richtext = regex.Replace(richtext, string.Empty);
}

// "_dx_frag_EndFragment" ausblenden
// exakte Einträge: "{\*\bkmkstart _dx_frag_EndFragment}" + "{\*\bkmkend _dx_frag_EndFragment}"
if (richtext.IndexOf("_dx_frag_EndFragment") > 0) {
var regex = new Regex(@"{\\\*\\bkmkstart _dx_frag_EndFragment}");
richtext = regex.Replace(richtext, string.Empty);
regex = new Regex(@"{\\\*\\bkmkend _dx_frag_EndFragment}");
richtext = regex.Replace(richtext, string.Empty);
}

//richtext = FixRtfBulletList (richtext);

// Bei ConvertRichText werden die RTF-Steuerwörter \bullet, \lquote, \rquote, \ldblquote und \rdblquote
// von FastReport verworfen (Zeichen fehlt in Vorschau/PDF). Die RichTextBox in NormalizeRichText erzeugt
// diese Steuerwörter selbst (z.B. aus dem Unicode-Zeichen U+2022), daher erst danach durch Unicode-Zeichen ersetzen.
if (SelectConvertRichtext == (int)Show.An) {
richtext = NormalizeRichText(richtext, SelectLeerzeileRTF == (int)Show.Aus);
richtext = FixRtfBulletIndent(richtext);
richtext = FixRtfSpecialChars(richtext);
}
return (richtext);
}

Je nach Alter deines Reports enthält der zu ersetzende Bereich nur eine oder mehrere Funktionen. Das spielt keine Rolle: Ersetze in jedem Fall den gesamten Bereich durch den neuen Block, damit keine Funktionen doppelt vorhanden sind.

Schritt 3: Schalter prüfen und ggf. ergänzen​

Suche im Codebereich nach selectLeerzeileRTF

  • Gefunden (Hybrid Kundenanlagen Report ab Version 24-2-0-SP): Hier ist nichts weiter zu tun.
  • Nicht gefunden (Hybrid Kundenanlagen Report ab Version 23-4-0-SP bis vor 24-2-0-SP): Füge die folgende Zeile ein:
private int SelectLeerzeileRTF = (int)Show.Aus;                // Schalter für: Bei "SelectConvertRichtext" Leerzeilen-Positionen als Richtext oder Plain-Text darstellen 

Wo muss die Zeile hin? Innerhalb der Klasse ReportScript, aber nicht innerhalb einer Funktion. Am einfachsten fügst du sie direkt unter einem anderen vorhandenen Schalter ein.

Screenshot: fehlerhafte Aufzählungszeichen

Wichtig: In älteren Reports ist dieser Schalter nicht vollumfänglich implementiert. Er muss lediglich vorhanden sein, damit der neue Codeblock funktioniert. Lass den Wert unverändert.

Fehlt der Schalter, erscheint beim Erstellen der Vorschau bzw. des PDFs ein Fehler wie:

The name 'select Leerzeile RTF' does not exist in the current context

Zur Info: Der Schalter sorgt dafür, dass leere Positionen als Plain Text statt als Rich Text ausgegeben werden. Dadurch werden zu große Abstände bei leeren Positionen vermieden.

Schritt 4: Testen​

Speichere den Report und erstelle erneut einen Testbeleg mit Aufzählungszeichen.


Ich möchte die Anpassung nicht selbst durchführen​

Für den Hybrid Kundenanlagen Report ab Version 23-4-0-SP übernimmt unser Consulting die beschriebenen Anpassungen gerne für dich, zum vergünstigten Stundensatz von 140 € statt 160 € (zzgl. MwSt.). In der Regel reicht ein 30-minütiger Termin, die Anpassung kostet dich also nur rund 70 € zzgl. MwSt. Einen Termin vereinbarst du über unser Buchungstool.


Mein Report ist älter als Version 23-4-0-SP​

Reports vor Version 23-4-0-SP sind zu alt für eine Korrektur. Ihnen fehlen die notwendigen Funktionen vollständig, sodass der Report nicht mehr sinnvoll repariert werden kann. Du hast folgende Möglichkeiten:

  • Aktuellen Standard-Report verwenden: Der aktuelle Hybrid Kundenanlagen Report Version 26-5-2-SP enthält bereits alle Korrekturen und steht im Report-Portal zur Verfügung.
  • Individuelle Anpassungen übernehmen lassen: Unser Consulting überträgt deine individuellen Anpassungen auf den aktuellen Hybrid Kundenanlagen Report Version 26-5-2-SP. Das wird nach Aufwand zum regulären Stundensatz abgerechnet; der vergünstigte Stundensatz gilt hierfür nicht.

Es tritt ein anderer Fehler auf, der hier nicht beschrieben ist​

Melde dich gerne mit einem Screenshot des fehlerhaften Belegs und der Angabe deiner Report-Version bei unserem Support. Wir prüfen, ob der Fehler mit der neuen FastReport-Version zusammenhängt, und ergänzen diese FAQ bei Bedarf.